/***
 * @Description: 本文件是关于IP协议的相关配置的头文件，主要包括数据结构定义，IPv4协议封装实现，IP数据包的收发解析，数据包分片重组实现等功能
 * @Author: Liverpool
 * @Date: 2024-07-03 01:58:03
 * @LastEditTime: 2024-07-03 01:58:45
 * @LastEditors: Liverpool
 */

#ifndef IPV4_H
#define IPV4_H

#include "netComman.h"
#include "ipaddr.h"
#include "list.h"
#include "ethernet.h"
#include "packet.h"

#define IPv4_MTU 1500 - 20    // IPv4单次能传输的最大数据量
#define NET_VERSION_IPV4 4    // 网络IP协议的版本号
#define NET_IP_DEFAULT_TTL 64 // IP数据报的默认生存时间(TTL)

#pragma pack(1) // 设置字节对齐为1

// IP数据报首部的数据结构定义
typedef struct _ipv4_header
{
    union // 对头部的16bit的数据定义联合体
    {
        struct
        {
// 为了解决大小端转化所出现的问题所以需要这样排布数据结构
#if NET_ENDIAN_LITTLE                 // 协议栈是小端存储
            uint16_t header_size : 4; // IP数据报的包头长度
            uint16_t version : 4;     // IP数据报的协议类型
            uint16_t tos : 8;         // IP数据报的区分服务
#else
            uint16_t version : 4;     // IP数据报的协议类型
            uint16_t header_size : 4; // IP数据报的包头长度
            uint16_t tos : 8;         // IP数据报的区分服务
#endif
        };
        uint16_t shotheader_all; // 头部16bit的数据
    };
    uint16_t total_len; // 总长度
    uint16_t Id;        // 标识
    union
    {
        struct
        {
#if NET_ENDIAN_LITTLE
            uint16_t offset : 13;      // 偏移地址，8字节为单位
            uint16_t more_flag : 1;    // 是否还有分片
            uint16_t disable_flag : 1; // 是否分片
            uint16_t reversed : 1;     //  预留
#else
            uint16_t reversed : 1;     //  预留
            uint16_t disable_flag : 1; // 是否分片
            uint16_t more_flag : 1;    // 是否还有分片片
            uint16_t offset : 13;      // 偏移地址，8字节为单位
#endif
        };
        uint16_t fragment_all; // 数据报(分包)：标志(3bit) + 偏移地址(15bit)
    };
    uint8_t ttl;                     // 生存时间
    uint8_t protocol;                // 数据部分的协议
    uint16_t header_checksum;        // 首部的校验和
    uint8_t src_ip[IPV4_ADDR_SIZE];  // 源地址
    uint8_t dest_ip[IPV4_ADDR_SIZE]; // 目的地址
} D_IPv4_Header;

typedef struct _ipv4_packet_header
{
    D_IPv4_Header header; // 头部
    uint8_t data[1];      // 数据区,只需要保存数据包的内存地址
} D_IPv4_Packet;
#pragma pack()

// 定义IPv4协议分片重组的相关数据结构
typedef struct _ipv4_fragment
{
    D_IP_ADDR ip;    // 分组的源IP地址
    uint16_t id;     // IPv4的标识符
    int ms;          // 分片超时
    D_List buf_list; // 收到的同一IP分组下的数据包
    D_ListNode node; // 不同ID下的IP分组的链表节点
} D_IPv4_Fragment;
//******************************************************外部函数接口************************************************************************** */
net_err_t ipv4_init(void);                                                            // IPv4协议的初始化
net_err_t ipv4_in(D_Net_Interface *netif, D_Packet *buf);                             // 对IP数据包进行输入解析处理
net_err_t ipv4_out(uint8_t protocol, D_IP_ADDR *dest, D_IP_ADDR *src, D_Packet *buf); // IPV4协议向外发送数据报
//******************************************************内联函数定义区************************************************************************** */

/***
 * @description: 计算得出IP数据包头部的数据长度
 * @Author: Liverpool
 * @Date: 2024-07-09 17:05:38
 * @return {*} IP数据包头部的数据长度
 * @param {D_IPv4_Packet} *packet IP数据包的内存地址
 */
inline int ipv4_header_size(D_IPv4_Packet *packet)
{
    // IP数据包的首部计数值单位是4B
    return packet->header.header_size * 4;
}

/***
 * @description: 设置IP数据报的头部的数据长度
 * @Author: Liverpool
 * @Date: 2024-07-09 17:05:38
 * @return {*}
 * @param {D_IPv4_Packet} *packet IP数据包的内存地址
 */
inline void ipv4_set_header_size(D_IPv4_Packet *packet, int header_size)
{
    packet->header.header_size = header_size / 4;
}
/***
 * @description: 得到ipv4数据报的payload大小
 * @Author: Liverpool
 * @Date: 2024-07-26 23:49:49
 * @return {*}
 * @param {D_IPv4_Packet} *packet IP数据包的内存地址
 */
inline int get_ipv4_data_size(D_IPv4_Packet *packet)
{
    return packet->header.total_len - ipv4_header_size(packet);
}
/***
 * @description: 得到IP数据报的分片结构中的起始位置
 * @Author: Liverpool
 * @Date: 2024-07-26 23:52:10
 * @return {*}
 * @param {D_IPv4_Packet} *packet IP数据包的内存地址
 */
inline uint16_t get_fragment_start(D_IPv4_Packet *packet)
{
    return packet->header.offset * 8;
}
/***
 * @description: 得到IP数据报的分片结构中的结束位置
 * @Author: Liverpool
 * @Date: 2024-07-26 23:52:10
 * @return {*}
 * @param {D_IPv4_Packet} *packet IP数据包的内存地址
 */
inline uint16_t get_fragment_end(D_IPv4_Packet *packet)
{
    return get_fragment_start(packet) + get_ipv4_data_size(packet);
}
#endif // !IPV4_H
